<template>
  <div class="typeTable-container">
    <PacvueTable
      ref="sTableRef"
      v-model:pagination="queryMerge"
      v-model:server-sorter="queryMerge"
      v-bind="$attrs"
      :columns="compatibleColumns"
      sticky
      :loading="{ spinning: loading }"
      :data-source="data"
      :custom-row="customRowConfig"
    >
      <template #headerCell="headerCellScoped">
        <TableHeaderCell
          v-bind="headerCellScoped"
        >
          <CustomHeader
            :compatible-columns="compatibleColumns"
            :header-cell-scoped="headerCellScoped"
          />
        </TableHeaderCell>

      </template>
      <template #bodyCell="bodyCellScoped">
        <TableBodyCell v-bind="bodyCellScoped">
          <CustomBody
            :compatible-columns="compatibleColumns"
            :data="data"
            :body-cell-scoped="bodyCellScoped"
          />
        </TableBodyCell>
      </template>
    </PacvueTable>
    <!-- lineClampTip -->
    <LineClampTip />
  </div>
</template>
<script>
import CustomHeader from './CustomHeader.vue'
import CustomBody from './CustomBody.vue'
import CommonMixin from './CommonMixin'
import RadioColumnMixin from './RadioColumnMixin'
import mitt from 'mitt'
import LineClampTip from './LineClampTip'
// import _ from 'lodash'
export default {
  name: 'TypeTable',
  components: {
    CustomHeader,
    CustomBody,
    LineClampTip

  },
  mixins: [CommonMixin, RadioColumnMixin],
  provide() {
    const { busEvent, tableIsInit } = this
    return {
      busEvent,
      tableIsInit
    }
  },
  props: {
    // table 数据
    data: {
      type: Array,
      default: () => []
    },
    // table 列配置
    columns: {
      type: Array,
      default: () => []
    },
    // loading
    loading: {
      type: Boolean,
      default: false
    },
    // 是否根据data展示column最大宽度
    isFullWidthOfData: {
      type: Boolean,
      default: undefined
    },
    // 是否在展开全部宽度的时候 已 fullNumber 计算虚拟视图最大宽度
    isFullWidthWithFullNumber: {
      type: Boolean,
      default: false
    },
    // 需要展示的最大宽度的 格式化类型列表
    fullWidthOfFormatTypes: {
      type: Array,
      default: () => ['money', 'number']
    },
    // 排序字段是否忽略 prop属性
    sortIgnoreProp: {
      type: Boolean,
      default: undefined
    },
    // 页码配置  排序配置 等合并到 query参数
    query: {
      type: Object,
      default() {
        return {
          pageNum: 1,
          pageSize: 50,
          total: 0,
          order: '',
          orderBy: ''
        }
      }
    },
    // 请求函数
    fetchFun: Function,
    // 格式化配置
    formatConfig: Object,
    // 拦截补丁函数
    formatPatch: Function,
    // 拦截代理函数
    formatProxy: Function,
    // 单元格空占位符
    columnEmptyText: String,
    // 是否显示分页
    showPagination: {
      type: Boolean,
      default: true
    },
    // 兼容 element-table 常用 Api
    rowClassName: [String, Function],
    rowStyle: [Function, Object]
  },
  emits: [
    // 兼容 element-table 常用 Api
    'sort-change',
    'page-current-change',
    'page-size-change',
    'row-click',
    'row-dblclick',
    'row-contextmenu',
    'row-mouseenter',
    'row-mouseleave',
    'radio-change',
    'radio-click'
  ],
  data() {
    return {
      // table 是否初始化完成
      tableIsInit: { value: false },
      // 兼容性的 columns
      compatibleColumns: [],
      // 分页排序参数合并
      queryMerge: null,
      // 事件对象
      busEvent: {
        value: null
      },
      // checkbox 内置数据
      checkboxColData: []
    }
  },
  watch: {
    // 获取 兼容性后的 columns
    columns: {
      deep: true,
      immediate: true,
      handler() {
        this.compatibleColumns = this.getCompatibleColumns(this.columns)
      }
    },
    // 监听分页排序参数变化
    query: {
      deep: true,
      immediate: true,
      handler() {
        this.queryMerge = this.getPageSortQueryMerge()
      }
    }
  },
  mounted() {
    // 添加事件总成
    this.busEvent.value = mitt()
    // table 初始化完成
    this.tableIsInit.value = true
  },
  beforeUnmount() {
    this.busEvent.value.all.clear()
    // this.busEvent.value = null
  },
  methods: {
    // 获取element-table组件实例
    getTableRef() {
      return this.$refs.sTableRef
    },
    // 自定义row事件
    customRowConfig(record) {
      // 自定义 class 与 style
      const { rowClassName, rowStyle } = this
      let classCustom
      if (rowClassName) {
        if (typeof rowClassName === 'string') {
          classCustom = rowClassName
        } else if (typeof rowClassName === 'function') {
          classCustom = rowClassName.bind({ record, row: record })
        }
      }
      let styleCustom
      if (rowStyle) {
        if (typeof rowStyle === 'function') {
          styleCustom = rowStyle.bind({ record, row: record })
        } else if (typeof rowStyle === 'object') {
          styleCustom = { ...rowStyle }
        }
      }
      return {
        class: classCustom,
        style: styleCustom,
        onClick: this.creatRowHandle('row-click', record), // 点击行
        onDblclick: this.creatRowHandle('row-dblclick', record),
        onContextmenu: this.creatRowHandle('row-contextmenu', record),
        onMouseenter: this.creatRowHandle('row-mouseenter', record), // 鼠标移入行
        onMouseleave: this.creatRowHandle('row-mouseleave', record)
      }
    },
    // 创建一个 row handle
    creatRowHandle(handleName, record) {
      const handleFun = (event) => {
        const row = record
        const index = this.data.indexOf(row)
        this.$emit(handleName, {
          record,
          event,
          row,
          index
        })
      }
      handleFun.bind(record)
      return handleFun
    },
    // 获取分页排序配置
    getPageSortQueryMerge() {
      const mergeConfig = {
        onServerSort: this.onServerSort,
        onPageChange: this.onPageChange,
        onPageSizeChange: this.onPageSizeChange,
        showQuickJumper: true,
        showSizeChanger: true,
        small: false,
        hideOnSinglePage: false,
        ...this.getUnTransferQuery()
      }
      if (!mergeConfig.total || this.showPagination === false) {
        Object.assign(mergeConfig, {
          showQuickJumper: false,
          showSizeChanger: false
        })
      }
      return mergeConfig
    },
    // 监听排序变化
    onServerSort(current, pageSize, orderAsc, orderByField) {
      const nextQuery = this.getTransferQuery(
        current,
        pageSize,
        orderAsc,
        orderByField
      )
      Object.assign(this.query, nextQuery)
      this.$emit('sort-change', nextQuery)
      if (this.fetchFun) {
        this.fetchFun(null, false, this.query)
      }
    },
    // 监听页码变化
    onPageChange(current, pageSize, orderAsc, orderByField) {
      const nextQuery = this.getTransferQuery(
        current,
        pageSize,
        orderAsc,
        orderByField
      )
      Object.assign(this.query, nextQuery)
      this.$emit('page-current-change', current)
      // 刷新 data
      if (this.fetchFun) {
        this.fetchFun(null, false, this.query)
      }
    },
    // 监听 页码数量变化
    onPageSizeChange(current, pageSize, orderAsc, orderByField) {
      const nextQuery = this.getTransferQuery(
        current,
        pageSize,
        orderAsc,
        orderByField
      )
      Object.assign(this.query, nextQuery)
      // 冒泡事件
      this.$emit('page-size-change', pageSize)
      // 刷新 data
      if (this.fetchFun) {
        Object.assign(this.query, { pageNum: 1 })
        this.fetchFun(null, true, this.query)
      }
    },
    // 获取反转后的 query
    getUnTransferQuery() {
      const { current, orderAsc, orderByField } = this.query
      return {
        ...this.query,
        current: this.getValueOfFilterUndefined(current, this.query.pageNum),
        orderAsc: this.getValueOfFilterUndefined(
          orderAsc,
          this.query.order === 'ascending'
        ),
        orderByField: this.getValueOfFilterUndefined(
          orderByField,
          this.query.orderByField
        )
      }
    },
    // 获取转换后的 queryObject
    getTransferQuery(current, pageSize, orderAsc, orderByField) {
      return {
        current,
        pageNum: current,
        pageSize,
        orderAsc,
        orderByField,
        order: orderAsc ? 'ascending' : 'descending',
        orderBy: orderByField
      }
    },
    // 获取排序默认配置
    getServeDefaultConfig() {
      return {
        orderAsc: false, // 初始化必须设置一个排序方式
        orderByField: '', // 初始化必须设置一个排序字段
        // 排序按钮点击回调函数
        onServerSort: this.onServerSort
      }
    },

    // 获取排序默认配置
    getPaginationDefaultConfig() {
      return {
        current: 1,
        pageSize: 10,
        total: 0,
        showQuickJumper: true,
        showSizeChanger: true,
        onPageChange: this.onPageChange, // 页码变化回调函数
        onPageSizeChange: this.onPageSizeChange // pageSize 变化回调函数
      }
    },

    // 得到处理后兼容性的columns配置
    getCompatibleColumns(columns = [], compatibleColumns = []) {
      if (columns?.length) {
        columns.forEach((colItem) => {
          const compatibleColItem = this.getCompatibleColumn({ ...colItem })
          compatibleColumns.push(compatibleColItem)
          if (compatibleColItem.children?.length) {
            compatibleColItem.children = []
            this.getCompatibleColumns(
              colItem.children,
              compatibleColItem.children
            )
          }
        })
      }
      return compatibleColumns
    },
    // 处理 兼容性 column配置函数
    getCompatibleColumn(originConfig) {
      const nextMergeConfig = this.getColMergeConfig({ ...originConfig })
      // nextMergeConfig.visible = this.getValueOfFilterUndefined(nextMergeConfig.visible, true)
      // key
      nextMergeConfig.key = this.getValueOfFilterUndefined(nextMergeConfig.key, nextMergeConfig.prop, nextMergeConfig.label)
      return nextMergeConfig
    },
    // 获取列合并配置  [label , prop  , align ,value ,minWidth ...]
    getColMergeConfig(colConfig) {
      const findTypeCol = { ...colConfig }
      let mergeTypeColConfig = this.mergeOfFilterUndefined(
        findTypeCol,
        this.$props
      )
      // 补丁设置合并
      if (this.patchConfig) {
        mergeTypeColConfig = this.mergeOfFilterUndefined(this.patchConfig, {
          ...mergeTypeColConfig
        })
      }
      const isCleanSlot = mergeTypeColConfig.isCleanSlot
      // 是否 叶子节点列配置
      const isLeafColumn = this.getValueOfFilterUndefined(() => {
        // 如果是 嵌套插槽  直接作为叶子节点
        if (isCleanSlot) {
          return true
        }
        if (!findTypeCol.children) {
          return true
        } else {
          if (
            Array.isArray(findTypeCol.children) &&
            findTypeCol.children.length
          ) {
            return false
          }
          return true
        }
      })
      // 列属性
      const type = this.getCurrentColumnType(mergeTypeColConfig.type)
      // 是否特殊列
      const isSpecialColumnAuto = this.isSpecialColumn(type)
      // 组件传值最大
      // 当自定义列配置存在的情况下 常用column配置参数都已自定义列配置权值为最大
      // 表头文本
      const label = this.getValueOfFilterUndefined(
        mergeTypeColConfig.title,
        mergeTypeColConfig.label,
        mergeTypeColConfig.name
      )

      // 格式化
      // 向下兼容 type
      const formatType = this.getCurrentFormatType(
        this.getValueOfFilterUndefined(mergeTypeColConfig.formatType, 'string')
      )

      // 对齐方式计算
      const align = this.getValueOfFilterUndefined(
        mergeTypeColConfig.align,
        () => {
          if (isCleanSlot) {
            return 'center'
          }
          // 非叶子节点列  直接阻断
          if (!isLeafColumn) {
            return 'center'
          }
          // 针对特殊列 默认居中对齐
          if (isSpecialColumnAuto) {
            return 'center'
          }
          return formatType === 'string' ? 'left' : 'right'
        }
      )
      // 兼容历史属性 sqlName
      // prop属性
      const prop = this.getValueOfFilterUndefined(
        mergeTypeColConfig.dataIndex,
        mergeTypeColConfig.prop,
        mergeTypeColConfig.sqlName
      )
      // 排序是否忽略 prop属性
      const sortIgnoreProp = this.getValueOfFilterUndefined(
        mergeTypeColConfig.sortIgnoreProp,
        false
      )
      // 排序字段
      const sortable = this.getValueOfFilterUndefined(
        mergeTypeColConfig.orderByField,
        mergeTypeColConfig.sortable,
        () => {
          if (isSpecialColumnAuto) {
            return null
          }
          if (sortIgnoreProp) {
            return null
          }
          if (isCleanSlot) {
            return null
          }
          if (isLeafColumn) {
            return prop
          }
          return null
        },
        null
      )
      // 表头提示
      const headerNotic = this.getValueOfFilterUndefined(() => {
        // 针对特殊列 禁止头部提示
        if (isSpecialColumnAuto) {
          return null
        }
      }, mergeTypeColConfig.headerNotic)

      // 多行溢出
      const lineClamp = this.getValueOfFilterUndefined(
        () => {
          if (isCleanSlot) {
            return null
          }
          // 非叶子节点列  直接阻断
          if (!isLeafColumn) {
            return null
          }
          // 针对特殊列
          if (isSpecialColumnAuto) {
            return null
          }
        },
        mergeTypeColConfig.lineClamp,
        2
      )

      // 插槽
      const slotName = this.getValueOfFilterUndefined(
        mergeTypeColConfig.slotName,
        () => {
          if (isSpecialColumnAuto) {
            if (type === 'index') {
              return 'index'
            }
            if (type === 'expand') {
              return 'expand'
            }
          }
        },
        'default'
      )

      // 宽度偏移量 对 width minWidth 都有作用
      const widthOffset = mergeTypeColConfig.widthOffset
      // 最小宽度偏移量 只对 minWidth 都有作用
      const minWidthOffset = mergeTypeColConfig.minWidthOffset
      // 固定宽度
      const customWidth = this.getValueOfFilterUndefined(
        mergeTypeColConfig.width,
        () => {
          if (isCleanSlot) {
            return
          }
          // 非叶子节点列  直接阻断
          if (!isLeafColumn) {
            return
          }
          if (isSpecialColumnAuto) {
            // 目前根据UI规范 selection 特殊列固定 32px
            // expand index 特殊列没有定义label的情况下 56px
            if (!label) {
              return 56
            } else {
              // 有 label的根据 label 计算
              return this.getWidthOfLabelText(label) + 20 + 5
            }
          }
        }
      )

      // 固定宽度加上偏移量
      const width =
        customWidth !== undefined
          ? parseFloat(customWidth || 0) + parseFloat(widthOffset || 0)
          : customWidth

      // 最小宽度
      const customMinWidth = this.getValueOfFilterUndefined(
        mergeTypeColConfig.minWidth,
        () => {
          if (isCleanSlot) {
            return
          }
          // 非叶子节点列  直接阻断
          if (!isLeafColumn) {
            return
          }
          // 针对特殊列  减少后续计算消耗
          if (isSpecialColumnAuto) {
            return
          }
          // 根据label  获取文字宽度
          const labelTextWidth = parseInt(this.getWidthOfLabelText(label)) + 5
          // 表头具有的padding 宽度
          const labelPaddingWidth = this.labelPaddingWidth
          // 排序icon占据宽度
          const labelSortableWidth = sortable ? this.labelSortableWidth : 0
          // 提示icon占据宽度
          const labelNoticWidth = headerNotic ? this.labelNoticWidth : 0

          return (
            labelTextWidth +
            labelPaddingWidth +
            labelSortableWidth +
            labelNoticWidth
          )
        }
      )
      // 增加的宽度偏移量 ## 宽度偏移量 与 最小宽度偏移量同时同在的情况下  已最小宽度偏移量为主
      const addMinWidthOffset = this.getValueOfFilterUndefined(
        minWidthOffset,
        widthOffset,
        0
      )
      // 最小宽度 加上偏移量
      const minWidth =
        customMinWidth !== undefined
          ? parseFloat(customMinWidth || 0) + parseFloat(addMinWidthOffset)
          : customMinWidth
      // 是否格式化
      const isFormat = this.getValueOfFilterUndefined(
        () => {
          if (isCleanSlot) {
            return
          }
          // 非叶子节点直接阻断
          if (!isLeafColumn) {
            return false
          }
          // 针对特殊列 减少后续格式化消耗
          if (isSpecialColumnAuto) {
            return false
          }
        },
        mergeTypeColConfig.isFormat,
        true
      )
      // 空文本显示
      const emptyText = this.getValueOfFilterUndefined(
        mergeTypeColConfig.emptyText,
        '--'
      )
      // 自定义表头渲染函数
      const _renderHeader = mergeTypeColConfig.renderHeader
      // 格式化配置
      const formatConfig = Object.assign(
        {},
        this.defaultFormatConfig,
        mergeTypeColConfig.formatConfig
      )
      // 补丁设置
      const patchConfig = this.patchConfig
      // 拦截前的配置
      const proxyBeforeConfig = Object.assign({}, mergeTypeColConfig, {
        // 以下需要特殊计算的 属性
        widthOffset,
        minWidthOffset,
        isSpecialColumnAuto,
        formatType,
        headerNotic,
        isFormat,
        slotName,
        lineClamp,
        emptyText,
        isLeafColumn,
        sortIgnoreProp,
        formatConfig,
        patchConfig,
        // 替换原有renderHeader
        renderHeader: null,
        _renderHeader,
        //  同 element table
        type,
        label,
        title: label,
        prop,
        dataIndex: prop,
        width,
        minWidth,
        sortable,
        orderByField: sortable,
        sortOrder: sortable,
        align
      })
      // 拦截后的配置
      const proxyAfterConfig = this.getProxyAfterConfig(proxyBeforeConfig)
      return proxyAfterConfig
    },
    // 配置拦截函数
    getProxyAfterConfig(beforeProxyConfig) {
      //  预留配置拦截 prop 接口
      if (this.configProxyFun && typeof this.configProxyFun === 'function') {
        return this.configProxyFun(beforeProxyConfig)
      }
      const afterProxyConfig = { ...beforeProxyConfig }
      // 开启展开宽度计算
      if (afterProxyConfig.isFullWidthOfData) {
        const {
          data,
          formatType,
          fullWidthOfFormatTypes,
          isSpecialColumnAuto,
          isLeafColumn,
          slotName,
          render,
          prop
        } = afterProxyConfig

        // data 不存在
        if (!data?.length) {
          return afterProxyConfig
        }
        // 非叶子节点直接阻断
        if (!isLeafColumn) {
          return afterProxyConfig
        }
        // 特殊列
        if (isSpecialColumnAuto) {
          return afterProxyConfig
        }
        // 没有 prop
        if (!prop) {
          return afterProxyConfig
        }
        // 具有插槽 或者 render  不确定因素太多 无法计算
        if (slotName !== 'default' || render) {
          return afterProxyConfig
        }
        // 类型列表为空
        if (!fullWidthOfFormatTypes?.length) {
          return afterProxyConfig
        }
        // 不在类型列表
        if (!fullWidthOfFormatTypes.includes(formatType)) {
          return afterProxyConfig
        }
        //  列最大宽度
        let colItemMaxViewWidth = 0
        // 修复渲染延迟  按照期望值去优先算宽度
        const copyProxyConfig = { ...afterProxyConfig }
        copyProxyConfig.formatConfig = { ...copyProxyConfig.formatConfig }
        if (copyProxyConfig.isFullWidthWithFullNumber) {
          copyProxyConfig.formatConfig.isFullNumber = true
        }
        // 根据字符长度筛选最大值
        data.forEach((dataItem) => {
          if (!dataItem) {
            return
          }
          const dataItemVal = dataItem[prop]
          const dataItemValType = typeof dataItemVal
          if (dataItemValType === 'number' || dataItemValType === 'string') {
            const dataItemFormatValOfView = this.getColumnValOfConfig({
              row: dataItem,
              column: null,
              $index: 0,
              $config: copyProxyConfig
            })
            const dataItemOfViewWidth = this.getWidthOfCellText(
              dataItemFormatValOfView
            )
            if (colItemMaxViewWidth < dataItemOfViewWidth) {
              colItemMaxViewWidth = dataItemOfViewWidth
            }
          }
        })
        const columnMaxDataInnerWidth = colItemMaxViewWidth + 5
        // 获取 header label 视图包裹文字的视图宽度( 不包括排序 提示等 )
        let labelInnerWidth = afterProxyConfig.minWidth - 10 * 2
        if (afterProxyConfig.sortable !== null) {
          labelInnerWidth -= this.labelSortableWidth
        }
        if (afterProxyConfig.headerNotic) {
          labelInnerWidth -= this.labelNoticWidth
        }
        // console.log(labelInnerWidth, columnMaxDataInnerWidth)
        if (columnMaxDataInnerWidth > labelInnerWidth) {
          afterProxyConfig.minWidth =
            afterProxyConfig.minWidth +
            columnMaxDataInnerWidth -
            labelInnerWidth
        }
      }
      return afterProxyConfig
    },
    // 参数合并排除 value === undefined
    mergeOfFilterUndefined(originObj, mergeObj) {
      const originCopyObj = Object.assign({}, originObj)
      Object.keys(mergeObj).forEach((mergeKey) => {
        const mergeVal = mergeObj[mergeKey]
        if (mergeVal !== undefined) {
          originCopyObj[mergeKey] = mergeVal
        }
      })
      return originCopyObj
    },

    // 是否为特殊列
    isSpecialColumn(colType) {
      return this.specialColumns.indexOf(colType) !== -1
    },
    // 根据 cell 单元格文本获取 cell inner宽度
    getWidthOfCellText(cellText) {
      if (!cellText) {
        return 0
      }
      let canvas = document.createElement('canvas')
      let context = canvas.getContext('2d')
      context.font = '100 12px/18px Helvetica,Arial,Helvetica Neue'
      const cellTextWidth = context.measureText(cellText).width
      canvas = null
      context = null
      return cellTextWidth
    },
    // 根据 label文本获取 inner宽度
    getWidthOfLabelText(label) {
      if (!label) {
        return
      }
      let canvas = document.createElement('canvas')
      let context = canvas.getContext('2d')
      context.font = '700 12px/18px Helvetica,Arial,Helvetica Neue'
      const labelNodeList = label.split('\n')
      const labelNodeWidthList = labelNodeList.map((labelNode) => {
        const labelNodeWidth = context.measureText(labelNode).width
        return labelNodeWidth
      })
      canvas = null
      context = null
      const maxLabelNodeWidth = Math.max(...labelNodeWidthList)
      return maxLabelNodeWidth
    },
    // 获取有效的列type
    getCurrentColumnType(colType) {
      if (colType && !this.isSpecialColumn(colType)) {
        return
      } else {
        return colType
      }
    },
    // 获取有效的格式化 type
    getCurrentFormatType(formatType) {
      if (formatType && this.formatTypeAllList.indexOf(formatType) === -1) {
        return 'string'
      } else {
        return formatType || 'string'
      }
    },
    // 对函数参数进行遍历  函数类型  会获取函数返回值
    // 直到获取非 undefined 参数值
    getValueOfFilterUndefined() {
      let weightVal
      for (let i = 0, len = arguments.length; i < len; i++) {
        const argItem = arguments[i]
        if (argItem !== undefined) {
          if (typeof argItem !== 'function') {
            weightVal = argItem
            break
          } else {
            const argFunVal = argItem()
            if (argFunVal !== undefined) {
              weightVal = argFunVal
              break
            }
          }
        }
      }
      return weightVal
    }
  }
}
</script>
<style lang="scss" scoped>

</style>
